package main;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import common.entities.enums.ACTION;
import common.entities.enums.ENTITIES;
import common.entities.enums.PATTERN;
import common.entities.enums.SEX;
import common.entities.nonpersistent.Game;
import common.entities.nonpersistent.GameQuestion;
import common.entities.persistent.*;
import kernel_db.interfaces.*;
import kernel_gui.interfaces.*;
import kernel_gui.interfaces.kernel_gui.*;
import kernel_db.db.*;



public class Kernel 
implements IKernelGeneral, IManageUser, IGame, IManageGenre, 
			IManageCountry, IManageActor, IManageDirector, 
			IManageMovies,IManageQuestions, IManageDataBase{

	private ExecutorService ThreadPool; 
	private IDB DB;
	private IGUI Gui;
	private User currUser;
	private boolean isAdmin;
	private Game game;
	private int MinimalYear, MaximalYear;
	
	public Kernel(IDB DataBase, int maximalYear){
		this.ThreadPool =  Executors.newCachedThreadPool(); 
		this.DB = DataBase;
		this.isAdmin = false;
		this.MinimalYear = Movie.releaseYearMinValue;
		this.MaximalYear = maximalYear;
		this.game = null;
	}
	


	private String fixEscapeCharacters(String stringToFix) {
		if (stringToFix==null){
			return null;
		}
		return stringToFix.replaceAll("['\"\\\\]", "\\\\$0");
	}

	
	public void setGui(IGUI gui){
		this.Gui = gui;
	}
	
	@Override
	public void exitMillioner(int requestId) {
		try {
			ThreadPool.shutdownNow();
			DB.clearParserParams(); 
			DB.closeAllConnections();
			System.exit(0);
		} catch (Exception e) {
			System.exit(0);
		}

	}
	
	@Override
	public void authenticateUser(final String userName, final String password,
			final boolean loggedAsAdmin, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (userName.contains("\\") || password.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				try{
					if (userName.length()==0 || password.length()==0){
						Gui.returnError(requestId, "One or more parameters is missing", false);
						return;
					}
					User aUser = DB.authenticateUser(
							new User(userName, 
									password));
					if (aUser != null){
						Gui.returnAnswer(requestId, true);
						currUser=aUser;
						if (loggedAsAdmin) isAdmin = true;
					}else{
						Gui.returnError(requestId, "Wrong User name or Password", false);
						return;
					}	
				}catch(DB_Error e){
					Gui.returnError(requestId,e.getMessage(), e.getErrorType());
				}
			}
			});
	}

	@Override
	public boolean isAdministrator() {
		return isAdmin;
	}
	
	@Override
	public void hallOfFame(final int numberOfUsers, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					List<User> hallList = DB.hallOfFame(numberOfUsers);
					if (hallList == null){
						Gui.returnError(requestId ,"Unexpected Error", false);
						return;
					}
					Gui.returnAnswer(requestId, hallList);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}	
			});
	}

	@Override
	public User getCurrentUser() {
		return currUser;
	}

	@Override
	public void logOut(int requestId) {
		currUser = null;
		isAdmin = false;
		Gui.returnAnswer(requestId, true);
	}

	//manage Users
	
	public void createUser(final String userName, final String password, final String authPassword, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					User.validateName(userName);
					User.validatePassword(password);
				}catch (IllegalArgumentException e){
					Gui.returnError(requestId, e.getMessage(), false);
					return;					
				}
				if (password.contains("\\") || userName.contains("\\")){
					Gui.returnError(requestId,"\\ is illegal character",false);
					return;
				}
				
				if (password.compareTo(authPassword)!=0){
					Gui.returnError(requestId,"Passwords do not match",false);
					return;
				}
				try{
					DB.actionUser(ACTION.CREATE, 
							new User(userName, password));
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId,e.getMessage(), e.getErrorType());
					return;
				}
			}
			});
	}


	public void updateUser(final User user, final String newUserName, final String newPassword,
			final String authNewPassword, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					if (user == null || user.getId()<0){
						Gui.returnError(requestId, "User info problem", false);
						return;	
					}
					if (newUserName.contains("\\") || newPassword.contains("\\")){
						Gui.returnError(requestId, "\\ is illegal character", false);
						return;	
					}
					User.validateName(newUserName);
					User.validatePassword(newPassword);
				}catch(IllegalArgumentException e){
					Gui.returnError(requestId, e.getMessage(), false);
					return;
				}
				if (newPassword.compareTo(authNewPassword) != 0){
					Gui.returnError(requestId, "Passwords do not match", false);
					return;
				}
				user.setName(newUserName);
				user.setPassword(newPassword);
				try{
					DB.actionUser(ACTION.UPDATE, user);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}
		});
	}


	@Override
	public void deleteUser(final User user,final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (user == null || user.getId()<0){
					Gui.returnError(requestId, "User info problem", false);
					return;	
				}
				if (user.getId() == currUser.getId()){
					Gui.returnError(requestId, "A user cannot delete his own account", false);
					return;						
				}
				try{
					DB.actionUser(ACTION.DELETE, user);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}
		});
		
	}

	@Override
	public void countUsers(final String userNameSubStr, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					int count;
					if (userNameSubStr == null){
						count = DB.countUsers("");
					}
					else{
						if (userNameSubStr.contains("\\")){
							Gui.returnError(requestId,"\\ is illegal character", false);
							return;
						}
						count = DB.countUsers(fixEscapeCharacters(userNameSubStr));
					}
					Gui.returnAnswer(requestId, count);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}
		});		
	}


	@Override
	public void getUsers(final String userNameSubStr, final int from, final int to,final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					String substr =( userNameSubStr==null) ? "" : userNameSubStr;
					if (substr.contains("\\")){
						Gui.returnError(requestId, "\\ is illegal character", false);
						return;
					}
					substr = fixEscapeCharacters(substr);
					List<User> userList = DB. getUsers(substr, from, to);
					if (userList == null){
						userList = new ArrayList<User>();
					}
					Gui.returnAnswer(requestId, userList);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}
		});	
	}

	
	//Game Methods
	@Override
	public void startGame(final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					List<GameQuestion> questionList = DB.generateGame();
					for (GameQuestion gq : questionList){
						gq.changeOrderAnswers();
					}
					game = new Game(questionList);
					Gui.returnAnswer(requestID, true);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}	
			});			
	}


	@Override
	public boolean hasNextQuestion() {
		if (game == null) return false;
		return game.hasNextQuestion();
	}

	@Override
	public GameQuestion nextQuestion() {
		if (game == null) return null;
		return game.NextQuestion();
	}

	@Override
	public boolean submitAnswer(int answerNumber) {
		if (game == null) return false;
		return game.submitAnswer(answerNumber);
	}

	@Override
	public GameQuestion helpWheelReplaceQuestion() {
		if (game == null) return null;
		return game.helpWheelReplaceQuestion();
	}


	@Override
	public int[] helpWheelFiftyFifty() {
		if (game == null) return null;
		return game.helpWheelFiftyFifty();
	}


	@Override
	public int helpWheelExtraTime() {
		if (game == null) return 0; 
		return game.helpWheelExtraTime();
	}


	@Override
	public void endGame(final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				currUser.addGamesPlayed();
				currUser.setMoneyWon(game.getScore() + currUser.getMoneyWon());
				if (game.getScore() > currUser.getPersonalRecord()) {
					currUser.setPersonalRecord(game.getScore());
				}
				try {
					DB.updateUserScore(currUser);
					Gui.returnAnswer(requestId, game.getScore());
				} catch (DB_Error e) {
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
					return;
				}
				game = null;
			}
		});

	}


	//IDBGenre

	@Override
	public void actionGenre(final ACTION action,final Genre genre, final int requestId){
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (action == null) {
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if (action != ACTION.CREATE && genre.getId() == -1) {
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if (action != ACTION.DELETE){
					if (genre.getName().length() ==0){
						Gui.returnError(requestId, "Genre name cannot be empty", false);
						return;				
					}
					if (genre.getName()!=null && genre.getName().contains("\\\\")){
						Gui.returnError(requestId, "\\ is illegal character", false);
						return;
					}
					try{
						Genre.validateName(genre.getName());
					}catch(IllegalArgumentException e){
						Gui.returnError(requestId,e.getMessage(), false);
						return;
					}
				}

				try {
					DB.actionGenre(action, genre);
					Gui.returnAnswer(requestId, true);
				} catch (DB_Error e) {
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}
		});
	}

	@Override
	public void countGenres(final String GenreSubStr, final Movie movie, final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					int count;
					String genreSub = (GenreSubStr==null) ? "" : GenreSubStr;
					if (genreSub.contains("\\")){
						Gui.returnError(requestID, "\\ is illegal character", false);
						return;
					}
					genreSub = fixEscapeCharacters(genreSub);
					if (movie == null || movie.getId() == -1){
						count = DB.countGenres(genreSub, null);
					}else{
						if (movie.getId() == -1){
							Gui.returnError(requestID, "Error", false);
							return;
						}
						count = DB.countGenres(genreSub, movie);
					}
					Gui.returnAnswer(requestID, count);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});
	}
	

	@Override
	public void getGenres(final String GenreSubStr, final int from, final int to, final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String genreSub = (GenreSubStr==null) ? "" : GenreSubStr;
				if (genreSub.contains("\\")){
					Gui.returnError(requestID, "\\ is illegal character", false);
					return;
				}
				genreSub = fixEscapeCharacters(genreSub);
	
				try{
					List<Genre> genreList = DB.getGenres(genreSub, from, to);
					Gui.returnAnswer(requestID, genreList);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});
	}
		
	
	//IManageContry

	@Override
	public void actionCountry(final ACTION action,final Country country, final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (action == null || (action != ACTION.CREATE && country.getId() == -1)){
					Gui.returnError(requestID, "Error", false);
					return;
				}

				if (action!=ACTION.DELETE){
					if (country.getName() ==null || country.getName().length()==0){
						Gui.returnError(requestID, "Coutry name cannot be empty", false);
						return;		
					}
				
					if (country.getName().contains("\\\\")){
						Gui.returnError(requestID, "\\ is illegal character", false);
						return;
					}
					try{
						Country.validateName(country.getName());	
					}catch(IllegalArgumentException e){
						Gui.returnError(requestID, e.getMessage(), false);
						return;
					}
				}
				try{
					DB.actionCountry(action, country);
					Gui.returnAnswer(requestID, true);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});	
	}
	


	@Override
	public void countCountries(final String countrySubStr,final Movie movie, final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					int count;
					String countryStr = (countrySubStr==null) ? "" : countrySubStr;
					if (countryStr.contains("\\")){
						Gui.returnError(requestID, "\\ is illegal character", false);
						return;
					}
					countryStr = fixEscapeCharacters(countryStr);
					if (movie == null || movie.getId() == -1){
						count = DB.countCountries(countryStr, null);
					}else{
						count = DB.countCountries(countryStr, movie);
					}
					Gui.returnAnswer(requestID, count);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});	
	}



	@Override
	public void getCountries(final String countrySubStr, final int from, final int to,final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String countryStr = (countrySubStr==null) ? "" : countrySubStr;
				if (countryStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				countryStr = fixEscapeCharacters(countryStr);
				try{
					List<Country> countryList = DB.getCountries(countryStr, from, to);
					Gui.returnAnswer(requestId, countryList);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}

	//IManageActor


	@Override
	public void actionActor(final ACTION action, final Actor actor, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (action == null || actor == null || (action != ACTION.CREATE && actor.getId() == -1)){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if (action != ACTION.DELETE && (actor.getFirstName().length() ==0 || 
						actor.getLastName().length()==0)){
					Gui.returnError(requestId, "Actor's first/last cannot be empty", false);
					return;				
				}
				if (action != ACTION.DELETE){
					if (actor.getFirstName().contains("\\\\") || 
								actor.getLastName().contains("\\\\")){
						Gui.returnError(requestId, "\\ is illegal character", false);
						return;	
					}
					try{
						Actor.validateFirstName(actor.getFirstName());
						Actor.validateLastName(actor.getLastName());
					}catch(IllegalArgumentException e){
						Gui.returnError(requestId, e.getMessage(), false);
						return;		
					}
				}
				try{
					DB.actionActor(action, actor);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});		
	}



	@Override
	public void countActors(final String firstNameSubStr,final String lastNameSubStr,
			final SEX sex, final Movie movie, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String firstStr = (firstNameSubStr==null)? "" : firstNameSubStr;
				String lastStr = (lastNameSubStr==null)? "" : lastNameSubStr;

				if (firstStr.contains("\\") || lastStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				firstStr = fixEscapeCharacters(firstStr);
				lastStr = fixEscapeCharacters(lastStr);
				if (movie!=null && movie.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					int count =  DB.countActors( firstStr,  lastStr, sex,  movie);
					Gui.returnAnswer(requestId, count);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}



	@Override
	public void getActors(final String firstNameSubStr, final String lastNameSubStr,
			final SEX sex, final Movie movie, final int from, final int to,
			final int requestId) {
	ThreadPool.execute(new Runnable() {
		public void run() {
			String firstStr = (firstNameSubStr==null)? "" : firstNameSubStr;
			String lastStr = (lastNameSubStr==null)? "" : lastNameSubStr;

			if (firstStr.contains("\\") || lastStr.contains("\\")){
				Gui.returnError(requestId, "\\ is illegal character", false);
				return;
			}
			firstStr = fixEscapeCharacters(firstStr);
			lastStr = fixEscapeCharacters(lastStr);
			
			if (movie!=null && movie.getId()==-1){
				Gui.returnError(requestId, "Error", false);
				return;
			}			
			try{
				List<Actor> actorsList =  DB.getActors(firstStr, lastStr, sex,  movie,  from,  to);
				Gui.returnAnswer(requestId, actorsList);
			}catch(DB_Error e){
				Gui.returnError(requestId, e.getMessage(), e.getErrorType());
			}
		}});	
	}



	@Override
	public void getActorMovies(final Actor actor, final int from, final int to, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (actor == null || actor.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;
				}				
				try{
					List<Movie> moviesList = DB.getActorMovies(actor, from, to);
					moviesList = (moviesList==null)? new ArrayList<Movie>() : moviesList;
					Gui.returnAnswer(requestId, moviesList);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
		}

	@Override
	public void deleteMovieFromActor(final Actor actor,final Movie movie,final int requestID) {
		ThreadPool.execute(new Runnable() {
		public void run() {
			if (actor == null || actor.getId() ==-1 || movie == null || movie.getId() == -1){
				Gui.returnError(requestID, "Error", false);
				return;
			}
			try{
				DB.deleteMovieFromActor(actor, movie);
				Gui.returnAnswer(requestID, true);
			}catch(DB_Error e){
				Gui.returnError(requestID, e.getMessage(), e.getErrorType());
			}
		}});
		
	}


	//IManageDirector

	@Override
	public void actionDirector(final ACTION action, final Director director, final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (action == null || director == null || (action != ACTION.CREATE && director.getId() == -1)){
					Gui.returnError(requestID, "Error", false);
					return;
				}
				if (action != ACTION.DELETE && (director.getFirstName().length() ==0 || 
						director.getLastName().length()==0)){
					Gui.returnError(requestID, "Director first/last cannot be empty", false);
					return;				
				}
				if (action != ACTION.DELETE){
					if (director.getFirstName().contains("\\\\") || 
							director.getLastName().contains("\\\\")){
						Gui.returnError(requestID, "\\ is illegal character", false);
						return;		
					}
					
					try{
						Director.validateFirstName(director.getFirstName());
						Director.validateLastName(director.getLastName());
					}catch(IllegalArgumentException e){
						Gui.returnError(requestID, e.getMessage(), false);
						return;		
					}
						
				}
				try{
					DB.actionDirector(action, director);
					Gui.returnAnswer(requestID, true);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});	
	}


	@Override
	public void countDirectors(final String firstNameSubStr, final String lastNameSubStr,
			final Movie movie, final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String firstStr = (firstNameSubStr==null)? "" : firstNameSubStr;
				String lastStr = (lastNameSubStr==null)? "" : lastNameSubStr;

				if (firstStr.contains("\\") || lastStr.contains("\\")){
					Gui.returnError(requestID, "\\ is illegal character", false);
					return;
				}
				firstStr = fixEscapeCharacters(firstStr);
				lastStr = fixEscapeCharacters(lastStr);
				
				if (movie!=null && movie.getId()==-1){
					Gui.returnError(requestID, "Error", false);
					return;
				}
				try{
					int count = DB.countDirectors(firstStr, lastStr, movie);
					Gui.returnAnswer(requestID, count);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});	
	}



	@Override
	public void getDirectors(final String firstNameSubStr, final String lastNameSubStr,
			final Movie movie,final int from,final int to,final int requestID) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String firstStr = (firstNameSubStr==null)? "" : firstNameSubStr;
				String lastStr = (lastNameSubStr==null)? "" : lastNameSubStr;

				if (firstStr.contains("\\") || lastStr.contains("\\")){
					Gui.returnError(requestID, "\\ is illegal character", false);
					return;
				}
				firstStr = fixEscapeCharacters(firstStr);
				lastStr = fixEscapeCharacters(lastStr);
				
				if (movie!=null && movie.getId()==-1){
					Gui.returnError(requestID, "Error", false);
					return;
				}
				try{
					List<Director> directorList = DB.getDirectors(firstStr, lastStr,movie,from, to);
					Gui.returnAnswer(requestID, directorList);
				}catch(DB_Error e){
					Gui.returnError(requestID, e.getMessage(), e.getErrorType());
				}
			}});	
	}



	@Override
	public void getDirectorMovies(final Director director, final int from, final int to,final int requestID) {
		ThreadPool.execute(new Runnable() {
		public void run() {
			if (director == null || director.getId()==-1){
				Gui.returnError(requestID, "Error", false);
				return;
			}
			try{
				List<Movie> moviesList = DB.getDirectorMovies(director, from, to);
				moviesList = (moviesList==null)? new ArrayList<Movie>() : moviesList;
				Gui.returnAnswer(requestID, moviesList);
			}catch(DB_Error e){
				Gui.returnError(requestID, e.getMessage(), e.getErrorType());
			}
		}});	
	}

	@Override
	public void deleteMovieFromDirector(final Director director, final Movie movie,
			final int requestID) {
		ThreadPool.execute(new Runnable() {
		public void run() {
			if (movie == null || director == null || movie.getId() == -1  || director.getId() == -1){
				Gui.returnError(requestID, "Error", false);
				return;
			}
			try{
				DB.deleteMovieFromDirector(director, movie);
				Gui.returnAnswer(requestID, true);
			}catch(DB_Error e){
				Gui.returnError(requestID, e.getMessage(), e.getErrorType());
			}
		}});
	}

	//IManageMovie
	
	@Override
	public void actionMovie(final ACTION action,final Movie movie, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (action == null || movie == null || (action != ACTION.CREATE && movie.getId() == -1)){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if 	(action != ACTION.DELETE && movie.getTitle().length()==0){
					Gui.returnError(requestId, "Movie's title cannot be empty", false);
					return;				
				}
				if (action != ACTION.DELETE){
					if (movie.getTitle().contains("\\\\")){
						Gui.returnError(requestId, "\\ is illegal character", false);
						return;	
					}
					if (movie.getReleaseYear()>MaximalYear || movie.getReleaseYear()<MinimalYear){
						Gui.returnError(requestId, 
								"Bad insert/update argument: release year must be between " +MinimalYear+ " - " + MaximalYear, 
								false);
						return;	
					}
					if (movie.getRank()>Movie.rankMaxValue || movie.getRank()<Movie.rankMinValue){
						Gui.returnError(requestId,
								"Bad insert/update argument: rank must be between " + 
										Movie.rankMinValue + " - " + Movie.rankMaxValue,
								false);
						return;	
					}
					try{
						Movie.validateTitle(movie.getTitle());
						Movie.validateRank(movie.getRank());
					}catch(IllegalArgumentException e){
						Gui.returnError(requestId, e.getMessage(), false);
						return;
					}
				}
				
				try{
					DB.actionMovie(action, movie);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}



	@Override
	public void countMovies(final String titleSubStr, final int releaseYearMin,
			final int releaseYearMax, final float rankMin, final float rankMax, final Actor actor,
			final Director director, final List<Genre> geners, final Country countries,
			final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String titleStr = (titleSubStr==null)? "" : titleSubStr;
				if (titleStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				titleStr = fixEscapeCharacters(titleStr);

				if ((releaseYearMin < MinimalYear || releaseYearMin>MaximalYear) && releaseYearMin!=-1){
					Gui.returnError(requestId, "Bad search argument: 'Year From' does not exist in the data base", false);
					return;
				}
				if ((releaseYearMax<MinimalYear || releaseYearMax>MaximalYear)  && releaseYearMax!=-1){
					Gui.returnError(requestId, "Bad search argument: 'Year To' does not exist in the data base", false);
					return;
				}
				
				if (releaseYearMax != -1 && releaseYearMin !=-1 && releaseYearMax<releaseYearMin){
					Gui.returnError(requestId, "Bad search arguments: 'Year From' is bigger than 'Year To'", false);
					return;					
				}
				if (rankMax!= -1 && rankMin!=-1 && rankMax<rankMin){
					Gui.returnError(requestId, "Bad search arguments: rank from is bigger than rank to", false);
					return;				
				}

				
				if (actor!= null && actor.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;				
				}
				if (director!= null && director.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;				
				}
				if (countries!= null && countries.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;				
				}
				if (geners != null) {
					for (Genre g : geners) {
						if (g != null && g.getId() == -1) {
							Gui.returnError(requestId, "Error", false);
							return;
						}
					}
				}
				if (rankMax!= -1 && rankMin!=-1 && rankMax<rankMin){
					Gui.returnError(requestId, "Bad search argument: min rank is bigger than max rank", false);
					return;				
				}
				
				try{
					int count = DB.countMovies(titleStr, releaseYearMin, releaseYearMax, rankMin,
							rankMax, actor, director, geners, countries);
					Gui.returnAnswer(requestId, count);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}



	@Override
	public void getMovies(final String titleSubStr, final int releaseYearMin,
			final int releaseYearMax, final float rankMin, final float rankMax, 
			final Actor actor,
			final Director director, final List<Genre> geners, final Country countries, 
			final int from, final int to,final int requestId) {	
		ThreadPool.execute(new Runnable() {
			public void run() {
				String titleStr = (titleSubStr==null)? "" : titleSubStr;
				if (titleStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				titleStr = fixEscapeCharacters(titleStr);
				if ((releaseYearMax<MinimalYear || releaseYearMax>MaximalYear)  && releaseYearMax!=-1){
					Gui.returnError(requestId, "Bad search argument: 'Year To' does not exist in the data base", false);
					return;
				}
				
				if (releaseYearMax != -1 && releaseYearMin !=-1 && releaseYearMax<releaseYearMin){
					Gui.returnError(requestId, "Bad search arguments: 'Year From' is bigger than 'Year To'", false);
					return;					
				}
				if (rankMax!= -1 && rankMin!=-1 && rankMax<rankMin){
					Gui.returnError(requestId, "Bad search arguments: rank from is bigger than rank to", false);
					return;				
				}
				
				if (actor!= null && actor.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;				
				}
				if (director!= null && director.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;				
				}
				if (countries!= null && countries.getId()==-1){
					Gui.returnError(requestId, "Error", false);
					return;				
				}
				if (geners!=null){
					for (Genre g: geners){
						if (g!= null && g.getId()==-1){
							Gui.returnError(requestId, "Error", false);
							return;				
						}
					}
				}
				if (releaseYearMax!= -1 && releaseYearMin!=-1 && releaseYearMax<releaseYearMin){
					Gui.returnError(requestId, "Bad search argument: min rank is bigger than max rank", false);
					return;				
				}
				
				if (releaseYearMax!= -1 && releaseYearMin!=-1 && releaseYearMax<releaseYearMin){
					Gui.returnError(requestId, "Bad search argument: min rank is bigger than max rank", false);
					return;				
				}
				
				try{
					List<Movie> movieList = DB.getMovies(titleStr, releaseYearMin, releaseYearMax, rankMin, rankMax, actor, director, geners, countries, from, to);
					movieList = (movieList==null)?new ArrayList<Movie>() : movieList;
					Gui.returnAnswer(requestId, movieList);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}

	@Override
	public void getMovieEntities(final Movie movie, final ENTITIES entity, final int from,
			final int to, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (movie == null || movie.getId() == -1 || entity == null){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					switch(entity){
					case ACTOR: 
						List<Actor> actorList = DB.getMovieActors(movie, from, to);
						actorList = (actorList==null) ? new ArrayList<Actor>() : actorList;
						Gui.returnAnswer(requestId, actorList);
						break;
					
					case DIRECTOR:
						List<Director> directorList = DB.getMovieDirectors(movie, from, to);
						directorList = (directorList==null) ? new ArrayList<Director>() : directorList;
						Gui.returnAnswer(requestId, directorList);
						break;
					
					case GENRE:
						List<Genre> genreList = DB.getMovieGenres(movie, from, to);
						genreList = (genreList==null) ? new ArrayList<Genre>() : genreList;
						Gui.returnAnswer(requestId, genreList);	
					case COUNTRY:
						List<Country> countryList = DB.getMovieCountries(movie, from, to);
						countryList = (countryList==null) ? new ArrayList<Country>() : countryList;
						Gui.returnAnswer(requestId, countryList);
					}
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}

	@Override
	public void actionEntityFromMovie(final ACTION action, final Movie movie,
			final ENTITIES entity, final int entityId, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if ((action!=ACTION.CREATE && entityId==-1) || movie == null || 
						movie.getId() == -1 || entity == null){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					DB.actionEntityFromMovie(action, movie, entity, entityId);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}
	
	
	//IManageQuestion

	@Override
	public void createQuestion(final PATTERN pattern, final int entityIdQ, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				Gui.returnAnswer(requestId, true);
			}});	
	}


	@Override
	public void countAnswers(final PATTERN pattern,final int entityIdQ,final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					int count = DB.countAnswers(pattern,  entityIdQ);
						Gui.returnAnswer(requestId, count);

				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}


	@Override
	public void getAnswers(final PATTERN pattern, final int entityIdQ, final int from, final int to,
			final int requestId){		
		ThreadPool.execute(new Runnable() {
		public void run() {
			if (pattern == null){
				Gui.returnError(requestId, "Error", false);
				return;
			}
			if (pattern == PATTERN.MOVIE_RELEASED_IN_YEAR && 
					( entityIdQ<MinimalYear || entityIdQ>MaximalYear)){
				Gui.returnError(requestId,
						"Bad insert argument: release year must be between " +MinimalYear+ " - " + MaximalYear, false);
				return;
			}
			try{
					switch (pattern) {
					case ACTOR_PLAYED_IN_MOVIE: {
						List<Actor> actorsList = DB.getAnswersActors(pattern,entityIdQ, from, to);
						actorsList = (actorsList==null) ? new ArrayList<Actor>() : actorsList;
						Gui.returnAnswer(requestId, actorsList);
						break;
					}
					case GENRE_OF_MOVIE: {
						List<Genre> genresList = DB.getAnswersGenres(pattern,entityIdQ,  from, to);
						genresList = (genresList==null) ? new ArrayList<Genre>() : genresList;
						Gui.returnAnswer(requestId, genresList);
						break;
					}
					default: {
						List<Movie> moviesList = DB.getAnswersMovies(pattern,entityIdQ, from, to);
						moviesList = (moviesList==null) ? new ArrayList<Movie>() : moviesList;
						Gui.returnAnswer(requestId, moviesList);
						break;
					}
					}//end switch

			}catch(DB_Error e){
				Gui.returnError(requestId, e.getMessage(), e.getErrorType());
			}
		}});
	}
	
	
	@Override 
	public void setRightAnswer(final PATTERN pattern, final int entityIdQ, final int entityIdA,
			final int QLevel, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null ||  QLevel<0){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if (entityIdQ<0 || entityIdA<0){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					DB.createQuestion(pattern,entityIdQ, entityIdA, QLevel);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});			
	}


	public void searchQuestioYear(final PATTERN pattern, final int minYear,
			final int maxYear, final int from, final int to, final int requestId){
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern != PATTERN.MOVIE_RELEASED_IN_YEAR){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if (minYear != -1 && (minYear < MinimalYear || minYear > MaximalYear)) {
						Gui.returnError(requestId, "Search parameter 'From Year' is not valid ", false);
						return;
				}
				if (maxYear != -1 && (maxYear < MinimalYear || maxYear > MaximalYear)) {
					Gui.returnError(requestId,"Search parameter 'To Year' is not valid ",false);
					return;
				}
				String min = (minYear == -1)? null : Integer.toString(minYear);
				String max = (maxYear == -1)? null : Integer.toString(maxYear);
			try{
				
				List<DBQuestion> questionList = 
				DB.getQuestions(pattern,min , max, from, to);
				questionList = (questionList == null) ? new ArrayList<DBQuestion>() : questionList;
				Gui.returnAnswer(requestId, questionList);
			}catch(DB_Error e){
				Gui.returnError(requestId, e.getMessage(), e.getErrorType());
			}
			}});}

	@Override
	public void countQuestionMovie(final PATTERN pattern, final String titleSubStr, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null || 
					(pattern != PATTERN.ACTOR_PLAYED_IN_MOVIE && pattern != PATTERN.GENRE_OF_MOVIE)){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				String titleStr = (titleSubStr==null)? "" : titleSubStr;
				if (titleStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				titleStr = fixEscapeCharacters(titleStr);
				try{
					int count = DB.countQuestionMovie(pattern, titleStr);
					Gui.returnAnswer(requestId, count);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});
	}

	@Override
	public void countQuestioPerson(final PATTERN pattern, final String firstNameSubStr, 
			final String lastNameSubStr, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String firstStr = (firstNameSubStr==null)? "" : firstNameSubStr;
				String lastStr = (lastNameSubStr==null)? "" : lastNameSubStr;

				if (firstStr.contains("\\") || lastStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				firstStr = fixEscapeCharacters(firstStr);
				lastStr = fixEscapeCharacters(lastStr);
				if (pattern == null || (pattern != PATTERN.MOVIE_DIRECTED_BY &&  pattern != PATTERN.MOVIE_ACTOR_IN)){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					int count = DB.countQuestioPerson(pattern, firstStr, lastStr);
					Gui.returnAnswer(requestId, count);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});
	}

	@Override
	public void countQuestioYear(final PATTERN pattern,final int minYear,final int maxYear,
			final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null  || pattern!=PATTERN.MOVIE_RELEASED_IN_YEAR){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				if ((minYear < MinimalYear || minYear>MaximalYear) && minYear!=-1){
					Gui.returnError(requestId, "Bad search argument: 'Year From' does not exist in the data base", false);
					return;
				}
				if ((maxYear<MinimalYear || maxYear>MaximalYear)  && maxYear!=-1){
					Gui.returnError(requestId, "Bad search argument: 'Year To' does not exist in the data base", false);
					return;
				}
				
				if (maxYear != -1 && minYear !=-1 && maxYear<minYear){
					Gui.returnError(requestId, "Bad search arguments: 'Year From' is bigger than 'Year To'", false);
					return;					
				}
				try{
					int count = DB.countQuestioYear( pattern,  minYear,  maxYear);
					Gui.returnAnswer(requestId, count);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});
	}
	
	@Override
	public void deleteQuestion(final PATTERN pattern, final int questionID, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					DB.deleteQuestion(pattern, questionID);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});	
	}

	@Override
	public void searchQuestionMovie(final PATTERN pattern, final String titleSubStr,
			final int from, final int to, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				if (pattern == null
						|| (pattern != PATTERN.ACTOR_PLAYED_IN_MOVIE && pattern != PATTERN.GENRE_OF_MOVIE)) {
					Gui.returnError(requestId, "Error", false);
					return;
				}
				String titleStr = (titleSubStr==null)? "" : titleSubStr;
				if (titleStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				titleStr = fixEscapeCharacters(titleStr);
				try{
					List<DBQuestion> movielist = DB.getQuestions(pattern, titleStr, from, to);
					movielist = (movielist==null) ? new ArrayList<DBQuestion>() : movielist;
					Gui.returnAnswer(requestId, movielist);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});
	}

	@Override
	public void searchQuestioPerson(final PATTERN pattern, final String firstNameSubStr,
			final String lastNameSubStr, final int from, final int to, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				String firstStr = (firstNameSubStr==null)? "" : firstNameSubStr;
				String lastStr = (lastNameSubStr==null)? "" : lastNameSubStr;

				if (firstStr.contains("\\") || lastStr.contains("\\")){
					Gui.returnError(requestId, "\\ is illegal character", false);
					return;
				}
				firstStr = fixEscapeCharacters(firstStr);
				lastStr = fixEscapeCharacters(lastStr);
				
				if (pattern == null || (pattern != PATTERN.MOVIE_DIRECTED_BY &&  pattern != PATTERN.MOVIE_ACTOR_IN)){
					Gui.returnError(requestId, "Error", false);
					return;
				}
				try{
					List<DBQuestion> questionList = DB.getQuestions(pattern, firstStr, lastStr, from, to);
					questionList = (questionList == null) ? new ArrayList<DBQuestion>() : questionList;
					Gui.returnAnswer(requestId, questionList);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});}
	
	//IManageDataBase
	
	@Override
	public void smallUpdate(final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					DB.smallUpdateDB();
					DB.clearParserParams(); 
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					DB.clearParserParams(); 
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
				
			}});
	}

	@Override
	public void largeUpdate(final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					DB.largeUpdateDB();
					DB.clearParserParams(); 
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					DB.clearParserParams(); 
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});
	}

	@Override
	public void generateQuestions(final int questionNum, final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					DB.generateQuestions(questionNum);
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});}

	@Override
	public void importToDB(final int requestId) {
		ThreadPool.execute(new Runnable() {
			public void run() {
				try{
					DB.importToDB();
					DB.clearParserParams(); 
					Gui.returnAnswer(requestId, true);
				}catch(DB_Error e){
					DB.clearParserParams(); 
					Gui.returnError(requestId, e.getMessage(), e.getErrorType());
				}
			}});
	}
}